plugin "alloy"

Set x {
    x.shape = Ellipse {
        strokeWidth : 0.0
        ry: 1.5 * x.shape.rx
    }

    x.text = Text {
      string : x.label
      x : x.shape.x
      y : x.shape.y + x.shape.ry + 20.0
    }

    x.minSizeFn = ensure minSize(x.shape)
    x.maxSizeFn = ensure maxSize(x.shape)
    LOCAL.layering  = x.shape below x.text
}

Point p
with Set A
where PointIn(A, p) {
    p.offset = 20.0
    p.shape = Circle {
        strokeWidth : 0
        color : rgba(0.0, 0.0, 0.0, 1.0)
        r : 3.0
        x : A.shape.x
    }

    p.text = Text {
        string : p.label
        x : p.shape.x + p.offset
        y : p.shape.y + p.offset
    }
    p.containsFn = ensure contains(A.shape, p.shape, 0.3 * A.shape.ry)
    p.layering = p.shape above A.shape
    p.textLayering = p.text above p.shape
}

Map f
with Set A; Set B
where From(f, A, B)
{
    A.shape.x = B.shape.x - A.shape.rx * 3.5
    B.shape.y = A.shape.y
    B.shape.rx = A.shape.rx
}

Point p; Point q
with Map f
where PairIn(p, q, f)
{
    p.mapShape = Arrow {
        startX : p.shape.x + p.offset
        startY : p.shape.y
        endX   : q.shape.x - p.offset
        endY   : q.shape.y
        thickness : 3.0
        arrowheadSize : 0.6
        color  : rgba(0.0, 0.0, 0.0, 1.0)
    }
    p.arrowLayering1 = p.mapShape above p.shape
    p.arrowLayering2 = p.mapShape above q.shape
}

Point p; Point q
with Set A
where PointIn(A, p); PointIn(A, q)
{
    LOCAL.repelFn = encourage repel(p.shape, q.shape, 0.0001)
    LOCAL.sameXFn = encourage equal(p.shape.x, q.shape.x)
}
